/*
 * Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @file
 * @brief FlashDB 公共 API 定义。
 *
 * FlashDB 提供了两类数据库：
 * - KVDB (Key-Value 数据库)：用于存储键值对配置/参数。
 * - TSDB (Time-series 数据库)：用于存储带时间戳的日志/记录。
 *
 * 同时提供了 blob API（处理二进制数据）和工具函数（如 CRC32）。
 */

#ifndef _FLASHDB_H_
#define _FLASHDB_H_

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdio.h>
#include <time.h>
#include <fdb_cfg.h>

#ifdef FDB_USING_FAL_MODE
#include <fal.h>
#endif

#include <fdb_def.h>

#ifdef __cplusplus
extern "C" {
#endif

/* ======================= Database 管理 API ======================= */

/**
 * @brief 初始化 KV 数据库。
 *
 * @param db         KV 数据库句柄（在外部分配好）。
 * @param name       数据库名称（逻辑标识，用于日志和调试）。
 * @param path       存储路径或 flash 分区名称。
 * @param default_kv 默认 KV 项数组（以 NULL 结尾），用于首次初始化或恢复默认配置。
 * @param user_data  用户私有数据指针，库内部不会使用，仅保存。
 *
 * @return fdb_err_t 0 表示成功，非 0 表示错误。
 */
fdb_err_t fdb_kvdb_init(fdb_kvdb_t db, const char *name, const char *path,
                        struct fdb_default_kv *default_kv, void *user_data);

/**
 * @brief 控制 KV 数据库的行为。
 *
 * @param db   数据库句柄。
 * @param cmd  控制命令，具体取值见 fdb_def.h 中定义。
 * @param arg  命令参数，可选。
 */
void fdb_kvdb_control(fdb_kvdb_t db, int cmd, void *arg);

/**
 * @brief 检查 KV 数据库的一致性并修复。
 *
 * @param db 数据库句柄。
 *
 * @return fdb_err_t 0 表示检查/修复成功。
 */
fdb_err_t fdb_kvdb_check(fdb_kvdb_t db);

/**
 * @brief 反初始化 KV 数据库。
 *
 * @param db 数据库句柄。
 *
 * @return fdb_err_t 0 表示成功。
 */
fdb_err_t fdb_kvdb_deinit(fdb_kvdb_t db);

/**
 * @brief 初始化 TSDB（时间序列数据库）。
 *
 * @param db       TSDB 句柄。
 * @param name     数据库名称。
 * @param path     存储路径或分区。
 * @param get_time 获取时间戳的回调函数，用于自动生成时间戳。
 * @param max_len  单条记录的最大长度（字节）。
 * @param user_data 用户私有数据。
 *
 * @return fdb_err_t 0 表示成功。
 */
fdb_err_t fdb_tsdb_init(fdb_tsdb_t db, const char *name, const char *path,
                        fdb_get_time get_time, size_t max_len, void *user_data);

/**
 * @brief 控制 TSDB 的行为。
 *
 * @param db   TSDB 句柄。
 * @param cmd  控制命令。
 * @param arg  命令参数。
 */
void fdb_tsdb_control(fdb_tsdb_t db, int cmd, void *arg);

/**
 * @brief 反初始化 TSDB。
 *
 * @param db TSDB 句柄。
 *
 * @return fdb_err_t 0 表示成功。
 */
fdb_err_t fdb_tsdb_deinit(fdb_tsdb_t db);

/* ======================= Blob API ======================= */

/**
 * @brief 创建一个 blob 描述结构。
 *
 * @param blob      blob 结构指针（由用户分配）。
 * @param value_buf 数据缓冲区指针。
 * @param buf_len   缓冲区长度。
 *
 * @return fdb_blob_t 初始化后的 blob。
 */
fdb_blob_t fdb_blob_make(fdb_blob_t blob, const void *value_buf, size_t buf_len);

/**
 * @brief 读取存储中的 blob 数据。
 *
 * @param db   数据库句柄。
 * @param blob blob 描述，包含用户提供的缓冲区。
 *
 * @return size_t 实际读取的字节数。
 */
size_t fdb_blob_read(fdb_db_t db, fdb_blob_t blob);

/* ======================= KV API ======================= */

/**
 * @brief 写入字符串类型的 KV。
 *
 * @param db    KV 数据库句柄。
 * @param key   键名。
 * @param value 字符串值。
 *
 * @return fdb_err_t 0 表示成功。
 */
fdb_err_t fdb_kv_set(fdb_kvdb_t db, const char *key, const char *value);

/**
 * @brief 获取字符串类型的 KV。
 *
 * @param db  KV 数据库句柄。
 * @param key 键名。
 *
 * @return char* 字符串值指针（可能需要用户释放，具体参考实现）。
 */
char *fdb_kv_get(fdb_kvdb_t db, const char *key);

/**
 * @brief 写入二进制 blob 类型的 KV。
 *
 * @param db   KV 数据库句柄。
 * @param key  键名。
 * @param blob 二进制数据描述。
 *
 * @return fdb_err_t 0 表示成功。
 */
fdb_err_t fdb_kv_set_blob(fdb_kvdb_t db, const char *key, fdb_blob_t blob);

/**
 * @brief 读取二进制 blob 类型的 KV。
 *
 * @param db   KV 数据库句柄。
 * @param key  键名。
 * @param blob 目标 blob（包含用户缓冲区）。
 *
 * @return size_t 实际读取字节数。
 */
size_t fdb_kv_get_blob(fdb_kvdb_t db, const char *key, fdb_blob_t blob);

/**
 * @brief 删除一个 KV。
 *
 * @param db  KV 数据库句柄。
 * @param key 键名。
 *
 * @return fdb_err_t 0 表示成功。
 */
fdb_err_t fdb_kv_del(fdb_kvdb_t db, const char *key);

/**
 * @brief 获取 KV 元信息对象。
 *
 * @param db KV 数据库句柄。
 * @param key 键名。
 * @param kv  用户提供的 KV 对象。
 *
 * @return fdb_kv_t KV 元信息对象。
 */
fdb_kv_t fdb_kv_get_obj(fdb_kvdb_t db, const char *key, fdb_kv_t kv);

/**
 * @brief 将 KV 对象转换为 blob 描述。
 *
 * @param kv   KV 元信息对象。
 * @param blob blob 结构。
 *
 * @return fdb_blob_t 转换后的 blob。
 */
fdb_blob_t fdb_kv_to_blob(fdb_kv_t kv, fdb_blob_t blob);

/**
 * @brief 恢复默认 KV（写入 default_kv 表）。
 *
 * @param db KV 数据库句柄。
 *
 * @return fdb_err_t 0 表示成功。
 */
fdb_err_t fdb_kv_set_default(fdb_kvdb_t db);

/**
 * @brief 打印所有 KV 项（用于调试）。
 *
 * @param db KV 数据库句柄。
 */
void fdb_kv_print(fdb_kvdb_t db);

/**
 * @brief 初始化 KV 迭代器。
 *
 * @param db  KV 数据库句柄。
 * @param itr 用户提供的迭代器结构。
 *
 * @return fdb_kv_iterator_t 初始化后的迭代器。
 */
fdb_kv_iterator_t fdb_kv_iterator_init(fdb_kvdb_t db, fdb_kv_iterator_t itr);

/**
 * @brief 遍历 KV 数据库。
 *
 * @param db  KV 数据库句柄。
 * @param itr 迭代器对象。
 *
 * @return bool true 表示获取到条目，false 表示结束。
 */
bool fdb_kv_iterate(fdb_kvdb_t db, fdb_kv_iterator_t itr);

/* ======================= TSDB API ======================= */

/**
 * @brief 追加一条时间序列记录（自动时间戳）。
 *
 * @param db   TSDB 句柄。
 * @param blob 数据 blob。
 *
 * @return fdb_err_t 0 表示成功。
 */
fdb_err_t fdb_tsl_append(fdb_tsdb_t db, fdb_blob_t blob);

/**
 * @brief 追加一条时间序列记录（指定时间戳）。
 *
 * @param db        TSDB 句柄。
 * @param blob      数据 blob。
 * @param timestamp 指定时间戳。
 *
 * @return fdb_err_t 0 表示成功。
 */
fdb_err_t fdb_tsl_append_with_ts(fdb_tsdb_t db, fdb_blob_t blob, fdb_time_t timestamp);

/**
 * @brief 按时间正序遍历 TSDB。
 *
 * @param db     TSDB 句柄。
 * @param cb     回调函数，每条记录调用一次。
 * @param cb_arg 回调参数。
 */
void fdb_tsl_iter(fdb_tsdb_t db, fdb_tsl_cb cb, void *cb_arg);

/**
 * @brief 按时间倒序遍历 TSDB。
 *
 * @param db     TSDB 句柄。
 * @param cb     回调函数。
 * @param cb_arg 回调参数。
 */
void fdb_tsl_iter_reverse(fdb_tsdb_t db, fdb_tsl_cb cb, void *cb_arg);

/**
 * @brief 遍历指定时间区间内的记录。
 *
 * @param db     TSDB 句柄。
 * @param from   起始时间。
 * @param to     结束时间。
 * @param cb     回调函数。
 * @param cb_arg 回调参数。
 */
void fdb_tsl_iter_by_time(fdb_tsdb_t db, fdb_time_t from, fdb_time_t to,
                          fdb_tsl_cb cb, void *cb_arg);

/**
 * @brief 查询指定时间区间内记录数量。
 *
 * @param db     TSDB 句柄。
 * @param from   起始时间。
 * @param to     结束时间。
 * @param status 记录状态筛选。
 *
 * @return size_t 记录数量。
 */
size_t fdb_tsl_query_count(fdb_tsdb_t db, fdb_time_t from, fdb_time_t to,
                           fdb_tsl_status_t status);

/**
 * @brief 设置某条记录的状态。
 *
 * @param db     TSDB 句柄。
 * @param tsl    记录对象。
 * @param status 新状态。
 *
 * @return fdb_err_t 0 表示成功。
 */
fdb_err_t fdb_tsl_set_status(fdb_tsdb_t db, fdb_tsl_t tsl, fdb_tsl_status_t status);

/**
 * @brief 清理 TSDB（删除旧记录/释放空间）。
 *
 * @param db TSDB 句柄。
 */
void fdb_tsl_clean(fdb_tsdb_t db);

/**
 * @brief 将一条时间序列记录转换为 blob。
 *
 * @param tsl  记录对象。
 * @param blob blob 描述。
 *
 * @return fdb_blob_t 转换后的 blob。
 */
fdb_blob_t fdb_tsl_to_blob(fdb_tsl_t tsl, fdb_blob_t blob);

/* ======================= 工具函数 ======================= */

/**
 * @brief 计算 CRC32 校验值。
 *
 * @param crc  初始 CRC 值（可为 0 或上一次计算结果，用于增量计算）。
 * @param buf  数据缓冲区。
 * @param size 数据长度（字节）。
 *
 * @return uint32_t CRC32 校验值。
 */
uint32_t fdb_calc_crc32(uint32_t crc, const void *buf, size_t size);

#ifdef __cplusplus
}
#endif

#endif /* _FLASHDB_H_ */
